using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
using System.Threading;

using Affirma.ThreeSharp;
using Affirma.ThreeSharp.Query;
using Affirma.ThreeSharp.Model;
using Affirma.ThreeSharp.Statistics;

namespace Affirma.CloudFront.AdminTool
{
    public partial class frmMain : Form
    {
        #region Constants

        const string BucketDetailRowHeaderName = "ObjectName";
        const string BucketDetailRowHeaderSize = "Size";
        const string BucketDetailRowHeaderUploaded = "Uploaded";
        const int MaxAllowedCNamesPerDistribution = 10;

        #endregion

        #region Variables

        private FolderTreeNode rootFolderNode;

        private BindingList<Affirma.ThreeSharp.Model.Transfer> transfers;
        private BindStatisticsDelegate bindStatisticsDelegate;
        private Boolean isRunning = true;
        private DownloadFileDelegate downloadFileDelegate;
        private frmStatistics statsDialog = new frmStatistics();
        private ListBucketDelegate listBucketDelegate;
        private Thread statsThread;
        private UploadFileDelegate uploadFileDelegate;
        private DistributionConfig distConfig;
        private XmlDocument distributionListXml = null;
        private SortedList<string, DistributionSummary> distributionList = new SortedList<string,DistributionSummary>();
        private DistributionInfo selectedDistribution;
        private LoadDistributionDelegate loadDistributionDelegate;
        private BindDistributionListDelegate bindDistributionListDelegate;
        private BindBucketListDelegate bindBucketListDelegate;
        private CopyTextToClipboardDelegate copyTextToClipboardDelegate;
        private ContextMenu dgvBucketContextMenu = new ContextMenu();
        private ContextMenu dgvBucketItemsContextMenu = new ContextMenu();

        #endregion

        #region Events


        private void frmMain_Load(object sender, EventArgs e)
        {
            if (AccountManager.Instance.LoadSavedAccounts())
            {
                this.Invoke(this.bindBucketListDelegate);
                this.Invoke(this.bindDistributionListDelegate, new object[] { false });
            }
            else
            {
                using (frmAccountManager f = new frmAccountManager())
                {
                    f.ShowDialog(this);
                }

                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    this.Invoke(this.bindBucketListDelegate);
                    this.Invoke(this.bindDistributionListDelegate, new object[] { false });
                }
            }

            this.ApplyStyles();

            this.treeViewFolders.frmMain = this;
            // creating am imagelist
            ImageList images = new ImageList();
            images.ColorDepth = ColorDepth.Depth32Bit;
            images.Images.Add(Image.FromStream(this.GetType().Assembly.GetManifestResourceStream("Affirma.CloudFront.AdminTool.folder.png")));
            this.treeViewFolders.Imagelist = images;

            statsThread = new Thread(new ThreadStart(this.StatsThreadMethod));
            statsThread.Start();


        }


        #region Button
        
        private void btnAddCName_Click(object sender, EventArgs e)
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstCNames.Items.Count < MaxAllowedCNamesPerDistribution)
                    {
                        string cname = this.txtCName.Text.ToLower().Trim();
                        bool duplicate = false;
                        foreach (object item in this.lstCNames.Items)
                        {
                            if (item.ToString().Trim().ToLower() == cname)
                            {
                                duplicate = true;
                                break;
                            }
                        }

                        if (duplicate)
                        {
                            MessageBox.Show("CNAME \"" + cname + "\" already exists. CNAMES must be unique.");
                            this.txtCName.SelectAll();
                        }
                        else
                        {
                            Regex regEx = new Regex("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$");
                            Match match = regEx.Match(cname);
                            if (match.Success)
                            {
                                this.lstCNames.Items.Add(cname);
                                this.txtCName.Text = string.Empty;
                            }
                            else
                            {
                                MessageBox.Show("CNAMES must be valid URLs.");
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show("The current distribution already contains " + MaxAllowedCNamesPerDistribution.ToString() + " CNAMES, which is the maximum allowed.  If you wish to add a new CNAME you must first remove an existing CNAME.");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnCreateBucket_Click(object sender, EventArgs e)
        {
            if (AccountManager.Instance.IsServiceSelected(true))
            {
                frmCreateBucket f = new frmCreateBucket();

                if (f.ShowDialog(this) == DialogResult.OK)
                    this.BindBucketNames();

                f.Dispose();
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            this.DeleteDistribution();
        }

        private void btnDeleteBucket_Click(object sender, EventArgs e)
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstBuckets.SelectedIndex > -1)
                    {
                        DialogResult result = MessageBox.Show(this, "Delete the selected bucket?", "Delete Bucket", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
                        if (result == DialogResult.Yes)
                        {
                            using (BucketDeleteRequest request = new BucketDeleteRequest(this.lstBuckets.SelectedItem.ToString()))
                            {
                                using (BucketDeleteResponse response = AccountManager.Instance.Service.BucketDelete(request))
                                {
                                    this.BindBucketNames();
                                }
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show("Please select a bucket to delete.");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnDeleteDistribution_Click(object sender, EventArgs e)
        {
   
            this.DeleteDistribution();
        }

        private void btnDeleteObject_Click(object sender, EventArgs e)
        {
            try
            {
                this.treeViewFolders.HideTreeView();

                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.dgvBucketItems.SelectedRows.Count == 0)
                        return;

                    DialogResult result = MessageBox.Show(this, string.Format("Are you sure you want to delete the object {0}?", this.dgvBucketItems.SelectedRows[0].Cells[BucketDetailRowHeaderName].Value.ToString()), "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
                    if (result != DialogResult.Yes)
                        return;

                    // The first thing we need to do is check for the presence of a Temporary Redirect.  These occur for a few
                    // minutes after an EU bucket is created, while S3 creates the DNS entries.  If we get one, we need to delete
                    // the file from the redirect URL

                    String redirectUrl = null;
                    using (BucketListRequest testRequest = new BucketListRequest(this.lstBuckets.SelectedItem.ToString()))
                    {
                        testRequest.Method = "HEAD";
                        using (BucketListResponse testResponse = AccountManager.Instance.Service.BucketList(testRequest))
                        {
                            if (testResponse.StatusCode == System.Net.HttpStatusCode.TemporaryRedirect)
                            {
                                redirectUrl = testResponse.Headers["Location"].ToString() + this.lstBuckets.SelectedItem.ToString();
                            }
                        }
                    }

                    using (ObjectDeleteRequest request = new ObjectDeleteRequest(this.lstBuckets.SelectedItem.ToString(), this.dgvBucketItems.SelectedRows[0].Cells[0].Value.ToString()))
                    {
                        request.RedirectUrl = redirectUrl;
                        using (ObjectDeleteResponse response = AccountManager.Instance.Service.ObjectDelete(request))
                        { }
                    }

                    this.ListBucket(this.lstBuckets.SelectedItem.ToString());
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnDownloadObject_Click(object sender, EventArgs e)
        {
            try
            {
                this.DownloadObject();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnRefreshBucketList_Click(object sender, EventArgs e)
        {
            if (AccountManager.Instance.IsServiceSelected(true))
            {
                this.Invoke(this.bindBucketListDelegate);
            }
        }

        private void btnRefreshObjectList_Click(object sender, EventArgs e)
        {
            try
            {
                this.treeViewFolders.HideTreeView();

                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstBuckets.SelectedIndex > -1)
                        this.Invoke(this.listBucketDelegate, new object[] { this.lstBuckets.SelectedItem.ToString() });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }        

        private void btnUploadObject_Click(object sender, EventArgs e)
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstBuckets.SelectedIndex > -1)
                    {
                        this.ofdUploadObject.FileName = string.Empty;
                        this.ofdUploadObject.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

                        if (this.ofdUploadObject.ShowDialog() == DialogResult.OK
                            && !string.IsNullOrEmpty(this.ofdUploadObject.FileName))
                        {
                            this.uploadFileDelegate.BeginInvoke(this.lstBuckets.SelectedItem.ToString(), this.ofdUploadObject.FileName, null, null);
                            this.ShowStatsDialog();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnSaveDistribution_Click(object sender, EventArgs e)
        {
            try
            {
                if(AccountManager.Instance.IsServiceSelected(true))
                {                    
                     if (this.selectedDistribution != null) // existing
                    {
                        this.selectedDistribution.DistributionConfig = this.AddUpdateConfigWithCNames(this.selectedDistribution.DistributionConfig);
                        this.selectedDistribution.DistributionConfig.Comment = this.txtDistComments.Text.Trim();
                        this.selectedDistribution.DistributionConfig.Enabled = this.chkEnabled.Checked;

                        using (DistributionUpdateRequest request = new DistributionUpdateRequest(this.selectedDistribution))
                        {
                            request.LoadStreamWithString(this.selectedDistribution.DistributionConfig.ToXml().InnerXml);
                            using (DistributionUpdateResponse response = AccountManager.Instance.Service.DistributionUpdate(request))
                            {                            
                                this.Invoke(this.bindDistributionListDelegate, new object[] { false });
                                MessageBox.Show("Distribution has been updated!");
                            }
                        }
                    }
                    else if (this.distConfig != null) // new
                    {
                        if (this.cboBuckets.SelectedItem != null)
                        {
                            this.distConfig.Origin = this.cboBuckets.SelectedItem.ToString();
                            this.distConfig.CallerReference = System.DateTime.Now.Ticks.ToString().Substring(0, 13);
                            this.distConfig = this.AddUpdateConfigWithCNames(this.distConfig);
                            this.distConfig.Comment = this.txtDistComments.Text.Trim();
                            this.distConfig.Enabled = this.chkEnabled.Checked;

                            using (DistributionAddRequest request = new DistributionAddRequest(distConfig))
                            {
                                request.LoadStreamWithString(distConfig.ToXml().InnerXml);
                                using (DistributionAddResponse response = AccountManager.Instance.Service.DistributionAdd(request))
                                {
                                    this.lstDistributions.SelectedIndex = -1;
                                    this.Invoke(this.bindDistributionListDelegate, new object[] { true });
                                    MessageBox.Show("Distribution has been created!");
                                }
                            }
                        }
                        else
                        {
                            MessageBox.Show("You must select an origin for the distribution");
                            this.cboBuckets.Select();
                            this.cboBuckets.DroppedDown = true;
                        }
                    }
                }       
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnNewDistribution_Click(object sender, EventArgs e)
        {
            if (AccountManager.Instance.IsServiceSelected(true))
            {
                this.distConfig = new DistributionConfig();
                this.ResetDistribution();
                this.lstDistributions.SelectedIndex = -1;
                this.cboBuckets.Focus();
                this.cboBuckets.DroppedDown = true;
            }
        }

        private void btnRefreshDistributionList_Click(object sender, EventArgs e)
        {
            if (AccountManager.Instance.IsServiceSelected(true))
            {
                this.Invoke(this.bindDistributionListDelegate, new object[] { false });
            }
        }           

        private void btnRemoveCName_Click(object sender, EventArgs e)
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstCNames.SelectedIndex > -1
                        && this.selectedDistribution != null
                        && this.selectedDistribution.DistributionConfig != null)
                    {
                        string selectedCName = this.lstCNames.SelectedItem.ToString();
                        this.selectedDistribution.DistributionConfig.CNames.Remove(selectedCName);
                        this.lstCNames.Items.Remove(selectedCName);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnRefreshDistributionList_MouseLeave(object sender, EventArgs e)
        {
            this.btnRefreshDistributionList.BackgroundImage = Properties.Resources.refresh2;
        }

        private void btnRefreshDistributionList_MouseHover(object sender, EventArgs e)
        {
            this.btnRefreshDistributionList.BackgroundImage = Properties.Resources.refresh2_h;
        }

        private void btnDeleteDistribution_MouseLeave(object sender, EventArgs e)
        {
            this.btnDeleteDistribution.BackgroundImage = Properties.Resources.delete;
        }

        private void btnDeleteDistribution_MouseHover(object sender, EventArgs e)
        {
            this.btnDeleteDistribution.BackgroundImage = Properties.Resources.delete_h;
        }

        private void btnNewDistribution_MouseLeave(object sender, EventArgs e)
        {
            this.btnNewDistribution.BackgroundImage = Properties.Resources._new;
        }

        private void btnNewDistribution_MouseHover(object sender, EventArgs e)
        {
            this.btnNewDistribution.BackgroundImage = Properties.Resources.new_h;
        }

        private void btnCreateBucket_MouseLeave(object sender, EventArgs e)
        {
            this.btnCreateBucket.BackgroundImage = Properties.Resources._new;
        }

        private void btnCreateBucket_MouseHover(object sender, EventArgs e)
        {
            this.btnCreateBucket.BackgroundImage = Properties.Resources.new_h;
        }

        private void btnDeleteBucket_MouseLeave(object sender, EventArgs e)
        {
            this.btnDeleteBucket.BackgroundImage = Properties.Resources.delete;
        }

        private void btnDeleteBucket_MouseHover(object sender, EventArgs e)
        {
            this.btnDeleteBucket.BackgroundImage = Properties.Resources.delete_h;
        }

        private void btnDeleteObject_MouseLeave(object sender, EventArgs e)
        {
            this.btnDeleteObject.BackgroundImage = Properties.Resources.delete;
        }

        private void btnDeleteObject_MouseHover(object sender, EventArgs e)
        {
            this.btnDeleteObject.BackgroundImage = Properties.Resources.delete_h;
        }

        private void btnDownloadObject_MouseHover(object sender, EventArgs e)
        {
            this.btnDownloadObject.BackgroundImage = Properties.Resources.download_h;
        }

        private void btnDownloadObject_MouseLeave(object sender, EventArgs e)
        {
            this.btnDownloadObject.BackgroundImage = Properties.Resources.download;
        }

        private void btnRefreshBucketList_MouseHover(object sender, EventArgs e)
        {
            this.btnRefreshBucketList.BackgroundImage = Properties.Resources.refresh2_h;
        }

        private void btnRefreshBucketList_MouseLeave(object sender, EventArgs e)
        {
            this.btnRefreshBucketList.BackgroundImage = Properties.Resources.refresh2;
        }

        private void btnRefreshObjectList_MouseHover(object sender, EventArgs e)
        {
            this.btnRefreshObjectList.BackgroundImage = Properties.Resources.refresh2_h;
        }

        private void btnRefreshObjectList_MouseLeave(object sender, EventArgs e)
        {
            this.btnRefreshObjectList.BackgroundImage = Properties.Resources.refresh2;
        }

        private void btnUploadObject_MouseHover(object sender, EventArgs e)
        {
            this.btnUploadObject.BackgroundImage = Properties.Resources.upload_h;
        }

        private void btnUploadObject_MouseLeave(object sender, EventArgs e)
        {
            this.btnUploadObject.BackgroundImage = Properties.Resources.upload;
        }
        
        private void btnAddCName_MouseHover(object sender, EventArgs e)
        {
            this.btnAddCName.BackgroundImage = Properties.Resources.plus2_h;
        }

        private void btnAddCName_MouseLeave(object sender, EventArgs e)
        {
            this.btnAddCName.BackgroundImage = Properties.Resources.plus2;
        }

        private void btnRemoveCName_MouseHover(object sender, EventArgs e)
        {
            this.btnRemoveCName.BackgroundImage = Properties.Resources.minus2_h;
        }

        private void btnRemoveCName_MouseLeave(object sender, EventArgs e)
        {
            this.btnRemoveCName.BackgroundImage = Properties.Resources.minus2;
        }

        private void btnBucketACL_MouseHover(object sender, EventArgs e)
        {
            this.btnBucketACL.BackgroundImage = Properties.Resources.lock_h;
        }

        private void btnBucketACL_MouseLeave(object sender, EventArgs e)
        {
            this.btnBucketACL.BackgroundImage = Properties.Resources._lock;
        }

        private void btnObjectACL_MouseHover(object sender, EventArgs e)
        {
            this.btnObjectACL.BackgroundImage = Properties.Resources.lock_h;
        }

        private void btnObjectACL_MouseLeave(object sender, EventArgs e)
        {
            this.btnObjectACL.BackgroundImage = Properties.Resources._lock;
        }


        #endregion

        #region DataGridView

        private void dgvBucketItems_DoubleClick(object sender, EventArgs e)
        {
            try
            {                
                this.DownloadObject();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void dgvBucketItems_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                DataGridView.HitTestInfo hti = this.dgvBucketItems.HitTest(e.X, e.Y);

                if (hti.Type == DataGridViewHitTestType.Cell
                    && e.Button == MouseButtons.Right)
                {
                    // Set focus to the row
                    this.dgvBucketItems.ClearSelection();
                    this.dgvBucketItems.Rows[hti.RowIndex].Cells[hti.ColumnIndex].Selected = true;

                    this.dgvBucketItemsContextMenu.MenuItems.Clear();
                    this.dgvBucketItemsContextMenu.MenuItems.Add(new MenuItem("Download", this.btnDownloadObject_Click));
                    this.dgvBucketItemsContextMenu.MenuItems.Add(new MenuItem("Copy URL to Clipboard", this.mniBucketItemCopyToClipboard_Click));

                    // Determine if bucket has distributions
                    if (this.lstDistributions.Items.Count > 0
                        && distributionList != null)
                    {
                        ArrayList subMenuItems = new ArrayList();

                        foreach (string key in this.distributionList.Keys)
                        {
                            string originName = this.distributionList[key].Origin.ToLower().Replace(".s3.amazonaws.com", string.Empty);

                            // If distribution, loop through and add each one
                            if (originName == this.lstBuckets.SelectedItem.ToString().ToLower())
                            {                                
                                for (int i = 0; i < this.distributionList[key].CNames.Count; i++)
                                {
                                    string cnameUrl = string.Format("http://{0}/{1}", this.distributionList[key].CNames[i], this.dgvBucketItems.SelectedRows[0].Cells[1].Value.ToString()).ToLower();
                                    subMenuItems.Add(new MenuItem(cnameUrl, this.mniBucketItemCopyUrlToClipboard_Click));
                                }                                
                            }
                        }

                        if (subMenuItems.Count > 0)
                        {
                            this.dgvBucketItemsContextMenu.MenuItems.Add("-");
                            this.dgvBucketItemsContextMenu.MenuItems.Add("Copy Distribution URLs", (MenuItem[])subMenuItems.ToArray(typeof(MenuItem)));
                        }                        
                    }

                    this.dgvBucketItemsContextMenu.MenuItems.Add("-");
                    this.dgvBucketItemsContextMenu.MenuItems.Add("Delete", btnDeleteObject_Click);

                    this.dgvBucketItemsContextMenu.Show(this.dgvBucketItems, e.Location);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region ListBox

        private void lstBuckets_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                if (e.Button == MouseButtons.Right)
                {
                    int rightClickIndex = this.lstBuckets.IndexFromPoint(e.X, e.Y);
                    if (this.lstBuckets.SelectedIndex != rightClickIndex)
                        this.lstBuckets.SelectedIndex = rightClickIndex;

                    this.lstBuckets.SuspendLayout();

                    if (this.lstBuckets.SelectedItem != null)
                    {
                        this.dgvBucketContextMenu.MenuItems.Clear();
                        this.dgvBucketContextMenu.MenuItems.Add(new MenuItem("Download", this.mniBucketDownload_Click));
                        this.dgvBucketContextMenu.MenuItems.Add(new MenuItem("Copy URL to Clipboard", this.mniBucketCopyToClipboard_Click));

                        // Determine if bucket has distributions
                        if (this.lstDistributions.Items.Count > 0
                            && distributionList != null)
                        {
                            ArrayList subMenuItems = new ArrayList();

                            foreach (string key in this.distributionList.Keys)
                            {
                                string originName = this.distributionList[key].Origin.ToLower().Replace(".s3.amazonaws.com", string.Empty);

                                // If distribution, loop through and add each one
                                if (originName == this.lstBuckets.SelectedItem.ToString().ToLower())
                                {
                                    for (int i = 0; i < this.distributionList[key].CNames.Count; i++)
                                    {
                                        string cnameUrl = string.Format("http://{0}", this.distributionList[key].CNames[i]).ToLower();
                                        subMenuItems.Add(new MenuItem(cnameUrl, this.mniBucketItemCopyUrlToClipboard_Click));
                                    }
                                }
                            }

                            if (subMenuItems.Count > 0)
                            {
                                this.dgvBucketContextMenu.MenuItems.Add("-");
                                this.dgvBucketContextMenu.MenuItems.Add("Copy Distribution URLs", (MenuItem[])subMenuItems.ToArray(typeof(MenuItem)));
                            }
                        }

                        this.dgvBucketContextMenu.MenuItems.Add("-");
                        this.dgvBucketContextMenu.MenuItems.Add("Delete", btnDeleteBucket_Click);
                        this.dgvBucketContextMenu.Show(this.lstBuckets, e.Location);
                    }

                    this.lstBuckets.ResumeLayout();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void lstBuckets_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    this.dgvBucketItems.ClearSelection();
                    this.dgvBucketItems.Rows.Clear();

                    if (this.lstBuckets.SelectedIndex > -1)
                        this.BeginInvoke(this.listBucketDelegate, new object[] { this.lstBuckets.SelectedItem.ToString() });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void lstDistributions_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (AccountManager.Instance.IsServiceSelected(true))
            {
                if (this.lstDistributions.SelectedIndex > -1
                    && this.distributionList.Count > 0)
                {
                    string domainName = this.lstDistributions.SelectedItem.ToString();
                    this.Invoke(loadDistributionDelegate, new object[] { domainName });
                }
            }
        }

        #endregion

        #region MenuItem

        private void mniFileExit_Click(object sender, EventArgs e)
        {
            statsThread.Abort();
            Application.Exit();
        }

        private void mniAccounts_Click(object sender, EventArgs e)
        {
            frmAccountManager f = new frmAccountManager();
            f.ShowDialog(this);
            f.Dispose();

            if (AccountManager.Instance.IsServiceSelected(true))
            {
                this.BeginInvoke(this.bindBucketListDelegate);
                this.BeginInvoke(this.bindDistributionListDelegate, new object[] { false });
            }
            else
            {
                this.lstDistributions.Items.Clear();
                this.lstBuckets.Items.Clear();
                this.dgvBucketItems.ClearSelection();
                this.dgvBucketItems.Rows.Clear();
                this.ResetDistribution();
            }
        }

        private void mniAbout_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process ieProcess = null;
            string aboutUrl = @"http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1855";
            
            try
            {
                ieProcess = System.Diagnostics.Process.Start("iexplore", aboutUrl);
            }
            catch (Exception)
            {
                if (ieProcess != null)
                    ieProcess.Kill();

                MessageBox.Show(this, "Unable to open URL: " + aboutUrl, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void mniStatistics_Click(object sender, EventArgs e)
        {
            this.ShowStatsDialog();
        }

        private void mniBucketDownload_Click(object sender, EventArgs e)
        {
            try
            {
                this.DownloadBucket();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void mniBucketCopyToClipboard_Click(object sender, EventArgs e)
        {
            try
            {
                this.copyTextToClipboardDelegate(string.Format("http://{0}.s3.amazonaws.com", this.lstBuckets.SelectedItem.ToString()));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void mniBucketItemCopyToClipboard_Click(object sender, EventArgs e)
        {
            try
            {
                this.copyTextToClipboardDelegate(string.Format("http://{0}.s3.amazonaws.com/{1}", this.lstBuckets.SelectedItem.ToString(), this.dgvBucketItems.SelectedRows[0].Cells[1].Value.ToString()));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void mniBucketItemCopyUrlToClipboard_Click(object sender, EventArgs e)
        {
            try
            {
                this.copyTextToClipboardDelegate(((MenuItem)sender).Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        protected override void OnClosing(CancelEventArgs e)
        {
            this.isRunning = false;

            base.OnClosing(e);
        }

        #endregion

        #region Constructors

        public frmMain()
        {
            InitializeComponent();

            this.Load += new EventHandler(frmMain_Load);
            this.dgvBucketItems.DoubleClick += new EventHandler(dgvBucketItems_DoubleClick);
            this.lstBuckets.MouseDown += new MouseEventHandler(lstBuckets_MouseDown);
            this.dgvBucketItems.MouseDown += new MouseEventHandler(dgvBucketItems_MouseDown);

            this.btnUploadObject.MouseHover += new EventHandler(btnUploadObject_MouseHover);
            this.btnUploadObject.MouseLeave += new EventHandler(btnUploadObject_MouseLeave);
            this.btnRefreshObjectList.MouseHover += new EventHandler(btnRefreshObjectList_MouseHover);
            this.btnRefreshObjectList.MouseLeave += new EventHandler(btnRefreshObjectList_MouseLeave);
            this.btnRefreshBucketList.MouseHover += new EventHandler(btnRefreshBucketList_MouseHover);
            this.btnRefreshBucketList.MouseLeave += new EventHandler(btnRefreshBucketList_MouseLeave);
            this.btnDownloadObject.MouseHover += new EventHandler(btnDownloadObject_MouseHover);
            this.btnDownloadObject.MouseLeave += new EventHandler(btnDownloadObject_MouseLeave);
            this.btnDeleteObject.MouseHover += new EventHandler(btnDeleteObject_MouseHover);
            this.btnDeleteObject.MouseLeave += new EventHandler(btnDeleteObject_MouseLeave);
            this.btnDeleteBucket.MouseHover += new EventHandler(btnDeleteBucket_MouseHover);
            this.btnDeleteBucket.MouseLeave += new EventHandler(btnDeleteBucket_MouseLeave);
            this.btnCreateBucket.MouseHover += new EventHandler(btnCreateBucket_MouseHover);
            this.btnCreateBucket.MouseLeave += new EventHandler(btnCreateBucket_MouseLeave);
            this.btnNewDistribution.MouseHover += new EventHandler(btnNewDistribution_MouseHover);
            this.btnNewDistribution.MouseLeave += new EventHandler(btnNewDistribution_MouseLeave);
            this.btnDeleteDistribution.MouseHover += new EventHandler(btnDeleteDistribution_MouseHover);
            this.btnDeleteDistribution.MouseLeave += new EventHandler(btnDeleteDistribution_MouseLeave);
            this.btnRefreshDistributionList.MouseHover += new EventHandler(btnRefreshDistributionList_MouseHover);
            this.btnRefreshDistributionList.MouseLeave += new EventHandler(btnRefreshDistributionList_MouseLeave);
            this.btnAddCName.MouseHover += new EventHandler(btnAddCName_MouseHover);
            this.btnAddCName.MouseLeave += new EventHandler(btnAddCName_MouseLeave);
            this.btnRemoveCName.MouseHover += new EventHandler(btnRemoveCName_MouseHover);
            this.btnRemoveCName.MouseLeave += new EventHandler(btnRemoveCName_MouseLeave);
            this.btnBucketACL.MouseHover += new EventHandler(btnBucketACL_MouseHover);
            this.btnBucketACL.MouseLeave += new EventHandler(btnBucketACL_MouseLeave);
            this.btnObjectACL.MouseHover += new EventHandler(btnObjectACL_MouseHover);
            this.btnObjectACL.MouseLeave += new EventHandler(btnObjectACL_MouseLeave);   

            this.transfers = new BindingList<Transfer>();
            this.statsDialog.StatsGrid.DataSource = transfers;
            this.statsDialog.ShowInTaskbar = false;
            this.statsDialog.Opacity = 0;
            this.statsDialog.Show();

            bindStatisticsDelegate = new BindStatisticsDelegate(this.BindStatistics);
            listBucketDelegate = new ListBucketDelegate(this.ListBucket);
            uploadFileDelegate = new UploadFileDelegate(this.UploadFile);
            downloadFileDelegate = new DownloadFileDelegate(this.DownloadFile);
            loadDistributionDelegate = new LoadDistributionDelegate(this.LoadDistribution);
            bindDistributionListDelegate = new BindDistributionListDelegate(this.BindDistributionNames);
            bindBucketListDelegate = new BindBucketListDelegate(this.BindBucketNames);
            copyTextToClipboardDelegate = new CopyTextToClipboardDelegate(this.CopyTextToClipboard);
        }
                
        #endregion

        #region Methods

        private DistributionConfig AddUpdateConfigWithCNames(DistributionConfig config)
        {
            try
            {
                foreach (object cname in this.lstCNames.Items)
                {
                    if (!config.CNames.Contains(cname.ToString()))
                        config.CNames.Add(cname.ToString());
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return config;
        }
           
        private void ApplyStyles()
        {
            Color hdrColor = Color.FromArgb(204, 199, 186);
            this.pnlTab1HdrLeft.BackColor = this.pnlTab1HdrRight.BackColor = this.panel5.BackColor = this.panel6.BackColor = hdrColor;
        }

        private void BindBucketNames()
        {
            try
            {
                this.lstBuckets.Items.Clear();
                this.cboBuckets.Items.Clear();

                using (BucketListRequest request = new BucketListRequest(null))
                using (BucketListResponse response = AccountManager.Instance.Service.BucketList(request))
                {
                    XmlDocument bucketXml = response.StreamResponseToXmlDocument();
                    XmlNodeList buckets = bucketXml.SelectNodes("//*[local-name()='Name']");

                    foreach (XmlNode bucket in buckets)
                    {
                        this.cboBuckets.Items.Add(bucket.InnerXml);
                        this.lstBuckets.Items.Add(bucket.InnerXml);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void BindDistributionNames(bool withNewItem)
        {
            try
            {
                string selectedItem = null;
                if (!withNewItem)
                {                        
                    if (this.lstDistributions.SelectedItem != null)
                        selectedItem = this.lstDistributions.SelectedItem.ToString();
                }

                this.lstDistributions.Items.Clear();
                this.distributionList.Clear();                    
                this.ResetDistribution();

                using (DistributionListRequest request = new DistributionListRequest())
                using (DistributionListResponse response = AccountManager.Instance.Service.DistributionList(request))
                {
                    distributionListXml = response.StreamResponseToXmlDocument();
                    XmlNodeList dsNodes = distributionListXml.SelectNodes("//*[local-name()='DistributionSummary']");

                    foreach (XmlNode dsNode in dsNodes)
                    {
                        if (dsNode.HasChildNodes)
                        {
                            DistributionSummary summary = new DistributionSummary();
                            foreach (XmlNode dsPropNode in dsNode.ChildNodes)
                            {
                                switch (dsPropNode.Name)
                                {
                                    case "Id":
                                        summary.Id = dsPropNode.InnerXml;
                                        break;

                                    case "Status":
                                        summary.Status = dsPropNode.InnerXml;
                                        break;

                                    case "LastModifiedTime":
                                        summary.LastModifiedTime = dsPropNode.InnerXml;
                                        break;

                                    case "DomainName":
                                        summary.DomainName = dsPropNode.InnerXml;
                                        break;

                                    case "Origin":
                                        summary.Origin = dsPropNode.InnerXml;
                                        break;

                                    case "Enabled":
                                        summary.Enabled = (dsPropNode.InnerXml == "true");
                                        break;

                                    case "CNAME":
                                        summary.CNames.Add(dsPropNode.InnerXml);
                                        break;

                                    case "Comment":
                                        summary.Comment = dsPropNode.InnerXml;
                                        break;
                                }
                            }

                            if (summary.DomainName != null)
                            {
                                this.distributionList.Add(summary.DomainName, summary);
                                this.lstDistributions.Items.Add(summary.DomainName);
                            }
                        }
                    }

                    if (withNewItem)
                    {
                        this.lstDistributions.SelectedIndex = this.lstDistributions.Items.Count -1;
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(selectedItem))
                        {
                            foreach (object listItem in this.lstDistributions.Items)
                            {
                                if (listItem.ToString() == selectedItem)
                                {
                                    this.lstDistributions.SelectedItem = listItem;
                                    break;
                                }
                            }

                            this.BeginInvoke(this.loadDistributionDelegate, new object[] { selectedItem.ToString() });
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void BindStatistics()
        {
            try
            {
                if (AccountManager.Instance.Service != null)
                {
                    Transfer[] grabbedTransfers = AccountManager.Instance.Service.GetTransfers();

                    foreach (Transfer transfer in grabbedTransfers)
                    {
                        if (!String.IsNullOrEmpty(transfer.BucketName) && !String.IsNullOrEmpty(transfer.Key))
                        {
                            int matchIndex = -1;
                            for (int i = 0; i < this.transfers.Count; i++)
                            {
                                if (this.transfers[i].ID == transfer.ID)
                                {
                                    matchIndex = i;
                                    break;
                                }
                            }
                            if (matchIndex > -1)
                            {
                                // Update the values
                                Transfer t = this.transfers[matchIndex];
                                t.BytesTransferred = transfer.BytesTransferred;
                                t.BytesTotal = transfer.BytesTotal;
                            }
                            else
                            {
                                // Add a new one to the DataGridView
                                this.transfers.Add(transfer);
                            }
                        }
                    }

                    if (this.statsDialog.StatsGrid.Rows.Count > 0)
                    {
                        this.statsDialog.StatsGrid.UpdateRowHeightInfo(0, true);
                        this.statsDialog.StatsGrid.Refresh();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void CopyTextToClipboard(string textToCopy)
        {
            try
            {
                Clipboard.SetDataObject(textToCopy, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void DeleteDistribution()
        {
            try
            {
                DialogResult result = MessageBox.Show(this, "Delete the selected distribution?", "Delete Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
                if (result == DialogResult.Yes)
                {
                    if (AccountManager.Instance.IsServiceSelected(true))
                    {
                        if (this.lstDistributions.SelectedIndex > -1
                            && this.selectedDistribution != null)
                        {
                            using (DistributionDeleteRequest request = new DistributionDeleteRequest(selectedDistribution))
                            {
                                using (DistributionDeleteResponse response = AccountManager.Instance.Service.DistributionDelete(request))
                                {
                                    this.lstDistributions.SelectedIndex = -1;
                                    MessageBox.Show("The selected distribution has been deleted.");
                                }
                            }

                            this.Invoke(this.bindDistributionListDelegate, new object[] { false });
                        }
                        else
                        {
                            MessageBox.Show("Please select a distribution to delete.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void DownloadFile(String bucketName, String basePath, String key)
        {
            // The first thing we need to do is check for the presence of a Temporary Redirect.  These occur for a few
            // minutes after an EU bucket is created, while S3 creates the DNS entries.  If we get one, we need to download
            // the file from the redirect URL

            this.treeViewFolders.HideTreeView();

            String redirectUrl = null;
            using (BucketListRequest testRequest = new BucketListRequest(bucketName))
            {
                testRequest.Method = "HEAD";
                using (BucketListResponse testResponse = AccountManager.Instance.Service.BucketList(testRequest))
                {
                    if (testResponse.StatusCode == System.Net.HttpStatusCode.TemporaryRedirect)
                    {
                        redirectUrl = testResponse.Headers["Location"].ToString() + key;
                    }
                }
            }

            try
            {
                using (ObjectGetRequest request = new ObjectGetRequest(bucketName, key))
                {
                    request.RedirectUrl = redirectUrl;
                    using (ObjectGetResponse response = AccountManager.Instance.Service.ObjectGet(request))
                    {
                        string path = Path.Combine(basePath, key.Replace('/', '-'));
                        response.StreamResponseToFile(path);
                    }
                }
            }
            // Suppress the exception since there is no UI to display to user 
            // and an exception would interupt a multiple file download
            catch (Exception) {} 
        }

        private void DownloadObject()
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstBuckets.SelectedIndex > -1
                        && this.dgvBucketItems.SelectedRows.Count > 0)
                    {
                        this.fbdDownloadObject.RootFolder = Environment.SpecialFolder.MyDocuments;
                        this.fbdDownloadObject.Description = "Select a location to download...";

                        DialogResult result = fbdDownloadObject.ShowDialog(this);
                        if (result == DialogResult.OK)
                        {
                            this.downloadFileDelegate.BeginInvoke(this.lstBuckets.SelectedItem.ToString(), this.fbdDownloadObject.SelectedPath, this.dgvBucketItems.SelectedRows[0].Cells[0].Value.ToString(), null, null);
                            this.ShowStatsDialog();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnObjectACL_Click(object sender, EventArgs e)
        {
            try
            {
                this.treeViewFolders.HideTreeView();

                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstBuckets.SelectedIndex > -1
                        && this.dgvBucketItems.Rows.Count > 0
                        && this.dgvBucketItems.SelectedRows.Count == 1)
                    {
                        string bucketName = this.lstBuckets.SelectedItem.ToString();
                        DataGridViewRow selectedRow = this.dgvBucketItems.SelectedRows[0];
                        string keyName = selectedRow.Cells[0].Value.ToString();
                        frmEditACL frmEditACL = new frmEditACL(bucketName, keyName);
                        frmEditACL.ShowDialog();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void DownloadBucket()
        {
            try
            {
                if (AccountManager.Instance.IsServiceSelected(true))
                {
                    if (this.lstBuckets.SelectedIndex > -1
                        && this.dgvBucketItems.Rows.Count > 0)
                    {
                        this.fbdDownloadObject.RootFolder = Environment.SpecialFolder.MyDocuments;
                        this.fbdDownloadObject.Description = "Select a location to download...";

                        DialogResult result = fbdDownloadObject.ShowDialog(this);
                        if (result == DialogResult.OK)
                        {
                            this.ShowStatsDialog();
                            foreach (DataGridViewRow row in this.dgvBucketItems.Rows)
                            {
                                this.downloadFileDelegate.BeginInvoke(this.lstBuckets.SelectedItem.ToString(), this.fbdDownloadObject.SelectedPath, row.Cells[BucketDetailRowHeaderName].Value.ToString(), null, null);
                                this.ShowStatsDialog();
                            }                           
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private string FormatDateTime(string xmlDate)
        {
            string formattedDate = string.Empty;

            try
            {
                formattedDate = Convert.ToDateTime(xmlDate.Replace("-", "/").Replace("T", " ").Replace("Z", string.Empty)).ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return formattedDate;
        }

        private void ListBucket(string bucketName)
        {
            try
            {
                this.treeViewFolders.HideTreeView();

                this.rootFolderNode = new FolderTreeNode(null);

                this.dgvBucketItems.ClearSelection();
                this.dgvBucketItems.Rows.Clear();

                // The first thing we need to do is check for the presence of a Temporary Redirect.  These occur for a few
                // minutes after an EU bucket is created, while S3 creates the DNS entries.  If we get one, we need to pull
                // the bucket listing from the redirect URL

                string redirectUrl = null;
                using (BucketListRequest testRequest = new BucketListRequest(bucketName))
                {
                    testRequest.Method = "HEAD";
                    using (BucketListResponse testResponse = AccountManager.Instance.Service.BucketList(testRequest))
                    {
                        if (testResponse.StatusCode == System.Net.HttpStatusCode.TemporaryRedirect)
                        {
                            redirectUrl = testResponse.Headers["Location"].ToString();
                        }
                    }
                }

                bool isTruncated = true;
                List<string> keyList = new List<string>(); 
                string marker = string.Empty;

                // The while-loop is here because S3 will only return a maximum of 1000 items at a time, so if the list
                // was truncated, we need to make another call and get the rest
                while (isTruncated)
                {
                    using (BucketListRequest request = new BucketListRequest(bucketName))
                    {
                        request.RedirectUrl = redirectUrl;
                        if (!string.IsNullOrEmpty(marker))
                            request.QueryList.Add("marker", marker);

                        using (BucketListResponse response = AccountManager.Instance.Service.BucketList(request))
                        {      
                            XmlDocument bucketXml = response.StreamResponseToXmlDocument();
                            XmlNodeList keys = bucketXml.SelectNodes("//*[local-name()='Key']");
                            XmlNodeList sizes = bucketXml.SelectNodes("//*[local-name()='Size']");
                            XmlNodeList dates = bucketXml.SelectNodes("//*[local-name()='LastModified']");

                            for (int i = 0; i < keys.Count; i++)
                            {
                                if (!keys[i].InnerText.EndsWith("_$folder$"))
                                {
                                    string lastModified = string.Empty;
                                    DateTime dateLastModified = DateTime.MinValue;
                                    if (DateTime.TryParse(dates[i].InnerText, out dateLastModified))
                                        lastModified = dateLastModified.ToString();

                                    keyList.Add(keys[i].InnerText);

                                    FolderTreeObject o = new FolderTreeObject(keys[i].InnerText, sizes[i].InnerText, lastModified);
                                    this.rootFolderNode.AddObject(o);
                                }
                            }

                            if (keyList.Count > 0)
                                marker = keyList[keyList.Count - 1];

                            isTruncated = bool.Parse(bucketXml.SelectSingleNode("//*[local-name()='IsTruncated']").InnerXml);
                        }
                    }
                }

                FillObjectList("/");
                FillFolderTreeView();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void FillFolderTreeView()
        {
            this.treeViewFolders.Nodes.Clear();
            this.treeViewFolders.Nodes.Add("/");
            this.treeViewFolders.txtValue.Text = "/";

            FillFolderTreeView(this.treeViewFolders.Nodes[0], this.rootFolderNode);
            this.treeViewFolders.Nodes[0].ExpandAll();
        }

        private void FillFolderTreeView(TreeNode node, FolderTreeNode folderNode)
        {
            if (node == null || folderNode == null)
            { return; }

            foreach (FolderTreeNode childFolder in folderNode.Children)
            {
                TreeNode childNode = new TreeNode(childFolder.Name);
                childNode.ImageIndex = 0;
                node.Nodes.Add(childNode);
                FillFolderTreeView(childNode, childFolder);
            }
        }


        public void FillObjectList(string folder)
        {
            this.dgvBucketItems.Rows.Clear();

            FolderTreeObject[] objects = this.rootFolderNode.GetObjects(folder);

            if (objects.Length > 0)
            {
                for (int i = 0; i < objects.Length; i++)
                {
                    object[] newRow = {objects[i].FullKeyName, objects[i].ShortKeyName, objects[i].Size, objects[i].Date };
                    this.dgvBucketItems.Rows.Add(newRow);
                }
            }

        }

        private void LoadDistribution(string domainName)
        {
            try
            {
                if (this.distributionList.Count > 0 && AccountManager.Instance.IsServiceSelected(true))
                {
                    DistributionSummary summary = this.distributionList[domainName];

                    using (DistributionGetRequest request = new DistributionGetRequest(summary.Id))
                    {
                        using (DistributionGetResponse response = AccountManager.Instance.Service.DistributionGet(request))
                        {
                            XmlDocument distributionInfoXml = response.StreamResponseToXmlDocument();
                            XmlNodeList dsNode = distributionInfoXml.SelectNodes("//*[local-name()='Distribution']");

                            foreach (XmlNode dsNodes in dsNode) // only 1 node at the level
                            {
                                this.ResetDistribution();
                                this.selectedDistribution = new DistributionInfo();
                                this.selectedDistribution.ETagHeader = response.Headers["ETag"].ToString();                                

                                foreach (XmlNode dsPropNode in dsNodes)
                                {
                                    switch (dsPropNode.Name)
                                    {
                                        case "Id":
                                            this.selectedDistribution.Id = dsPropNode.InnerXml;
                                            break;

                                        case "Status":
                                            this.selectedDistribution.Status = dsPropNode.InnerXml.Replace("InProgress", "In Progress");
                                            this.txtDistStatus.Text = this.selectedDistribution.Status;
                                            break;

                                        case "LastModifiedTime":
                                            this.selectedDistribution.LastModifiedTime = dsPropNode.InnerXml;
                                            this.txtLastModifiedDate.Text = this.FormatDateTime(this.selectedDistribution.LastModifiedTime);
                                            break;

                                        case "DomainName":
                                            this.selectedDistribution.DomainName = dsPropNode.InnerXml;
                                            this.txtDomainName.Text = this.selectedDistribution.DomainName;
                                            break;

                                        case "DistributionConfig":
                                            if (dsPropNode.HasChildNodes)
                                            {
                                                DistributionConfig config = new DistributionConfig();
                                                foreach (XmlNode dsChildNode in dsPropNode.ChildNodes)
                                                {
                                                    switch (dsChildNode.Name)
                                                    {
                                                        case "Origin":
                                                            config.Origin = dsChildNode.InnerXml;
                                                            foreach (object bucket in this.cboBuckets.Items)
                                                            {
                                                                if (bucket.ToString() == config.Origin.Replace(".s3.amazonaws.com", string.Empty))
                                                                {
                                                                    this.cboBuckets.SelectedItem = bucket;
                                                                    break;
                                                                }
                                                            }
                                                            break;

                                                        case "CallerReference":
                                                            config.CallerReference = dsChildNode.InnerXml;
                                                            break;

                                                        case "CNAME":
                                                            config.CNames.Add(dsChildNode.InnerXml);
                                                            this.lstCNames.Items.Add(dsChildNode.InnerXml);
                                                            break;

                                                        case "Comment":
                                                            config.Comment = dsChildNode.InnerXml;
                                                            this.txtDistComments.Text = config.Comment;
                                                            break;

                                                        case "Enabled":
                                                            config.Enabled = (dsChildNode.InnerXml == "true");
                                                            this.chkEnabled.Checked = config.Enabled;
                                                            break;
                                                    }
                                                }

                                                this.selectedDistribution.DistributionConfig = config;
                                            }
                                            break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ResetDistribution()
        {
            this.selectedDistribution = null;
            this.txtDomainName.Text = string.Empty;
            this.txtDistStatus.Text = string.Empty;
            this.txtLastModifiedDate.Text = string.Empty;
            this.cboBuckets.SelectedIndex = -1;
            this.txtCName.Text = string.Empty;
            this.lstCNames.Items.Clear();
            this.txtDistComments.Text = string.Empty;            
        }

        private void ShowStatsDialog()
        {
            this.statsDialog.BringToFront();
            this.statsDialog.Opacity = 100;
        }
        
        private void StatsThreadMethod()
        {
            while (this.isRunning)
            {
                this.statsDialog.StatsGrid.Invoke(this.bindStatisticsDelegate);
                System.Threading.Thread.Sleep(1000);
            }
        }

        private void UploadFile(string bucketName, string fullFileName)
        {
            // The first thing we need to do is check for the presence of a Temporary Redirect.  These occur for a few
            // minutes after an EU bucket is created, while S3 creates the DNS entries.  If we get one, we need to upload
            // the file to the redirect URL

            this.treeViewFolders.HideTreeView();

            string redirectUrl = null;
            FileInfo file = new FileInfo(fullFileName);
            string filename = file.Name;

            string folderPath = this.treeViewFolders.txtValue.Text;
            if (folderPath.StartsWith("/"))
            {
                folderPath = folderPath.Substring(1);
            }
            if (folderPath.Length > 0 && !folderPath.EndsWith("/"))
            {
                folderPath += "/";
            }

            filename = folderPath + filename;

            if (file.Exists)
            {
                using (BucketListRequest testRequest = new BucketListRequest(bucketName))
                {
                    testRequest.Method = "HEAD";
                    using (BucketListResponse testResponse = AccountManager.Instance.Service.BucketList(testRequest))
                    {
                        if (testResponse.StatusCode == System.Net.HttpStatusCode.TemporaryRedirect)
                        {
                            redirectUrl = testResponse.Headers["Location"].ToString() + filename.Replace(' ', '_');
                        }
                    }
                }

                using (ObjectAddRequest request = new ObjectAddRequest(bucketName, filename.Replace(' ', '_')))
                {
                    request.Headers.Add("x-amz-acl", "public-read");
                    request.LoadStreamWithFile(fullFileName);

                    if (redirectUrl != null)
                    {
                        request.RedirectUrl = redirectUrl;
                    }

                    using (ObjectAddResponse response = AccountManager.Instance.Service.ObjectAdd(request))
                    { }
                }
            }

            this.Invoke(listBucketDelegate, new object[] { bucketName });
        }    

        #endregion

        #region Delegates

        private delegate void CopyTextToClipboardDelegate(string textToCopy);
        public delegate void BindBucketListDelegate();
        public delegate void BindStatisticsDelegate();
        public delegate void BindDistributionListDelegate(bool newItemAdded);
        public delegate void DownloadFileDelegate(String bucketName, String basePath, String key);
        public delegate void ListBucketDelegate(string bucketName);
        public delegate void LoadDistributionDelegate(string domainName);
        public delegate void UploadFileDelegate(String bucketName, String filename);        

        #endregion                                           

        private void tableLayoutPanel3_Paint(object sender, PaintEventArgs e)
        {

        }

    }
}